﻿using System;
using EnvDTE;

namespace Agile.VSIX {
    /// <summary>
    /// 用于封装删除空白的逻辑的类
    /// </summary>
    internal class RemoveWhitespaceLogic {
        #region Methods

        /// <summary>
        /// Removes blank lines from the bottom of the specified text document.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveBlankLinesAtBottom(TextDocument textDocument) {
            EditPoint cursor = textDocument.EndPoint.CreateEditPoint();
            cursor.DeleteWhitespace(vsWhitespaceOptions.vsWhitespaceOptionsVertical);
        }

        /// <summary>
        /// Removes blank lines from the top of the specified text document.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveBlankLinesAtTop(TextDocument textDocument) {
            EditPoint cursor = textDocument.StartPoint.CreateEditPoint();
            cursor.DeleteWhitespace(vsWhitespaceOptions.vsWhitespaceOptionsVertical);
        }

        /// <summary>
        /// Removes blank lines after attributes.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveBlankLinesAfterAttributes(TextDocument textDocument) {
            const string pattern = @"(^[ \t]*\[[^\]]+\][ \t]*(//[^\r\n]*)*)(\r?\n){2}(?![ \t]*//)";
            string replacement = @"$1" + Environment.NewLine;

            TextDocumentHelper.SubstituteAllStringMatches(textDocument,pattern,replacement);
        }

        /// <summary>
        /// Removes blank lines after an opening brace.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveBlankLinesAfterOpeningBrace(TextDocument textDocument) {
            const string pattern = @"\{([ \t]*(//[^\r\n]*)*)(\r?\n){2,}";
            string replacement = @"{$1" + Environment.NewLine;

            TextDocumentHelper.SubstituteAllStringMatches(textDocument,pattern,replacement);
        }

        /// <summary>
        /// Removes blank lines before a closing brace.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveBlankLinesBeforeClosingBrace(TextDocument textDocument) {
            const string pattern = @"(\r?\n){2,}([ \t]*)\}";
            string replacement = Environment.NewLine + @"$2}";

            TextDocumentHelper.SubstituteAllStringMatches(textDocument,pattern,replacement);
        }

        /// <summary>
        /// Removes blank lines before a closing tag.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveBlankLinesBeforeClosingTag(TextDocument textDocument) {
            const string pattern = @"(\r?\n){2,}([ \t]*)</";
            string replacement = Environment.NewLine + @"$2</";

            TextDocumentHelper.SubstituteAllStringMatches(textDocument,pattern,replacement);
        }

        /// <summary>
        /// Removes blank lines between chained statements.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveBlankLinesBetweenChainedStatements(TextDocument textDocument) {
            const string pattern = @"(\r?\n){2,}([ \t]*)(else|catch|finally)( |\t|\r?\n)";
            string replacement = Environment.NewLine + @"$2$3$4";

            TextDocumentHelper.SubstituteAllStringMatches(textDocument,pattern,replacement);
        }

        /// <summary>
        /// Removes blank spaces before a closing angle bracket.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveBlankSpacesBeforeClosingAngleBracket(TextDocument textDocument) {
            // Remove blank spaces before regular closing angle brackets.
            const string pattern = @"(\r?\n)*[ \t]+>\r?\n";
            string replacement = @">" + Environment.NewLine;

            TextDocumentHelper.SubstituteAllStringMatches(textDocument,pattern,replacement);
        }

        /// <summary>
        /// Removes the trailing newline from the end of the specified text document.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveEOFTrailingNewLine(TextDocument textDocument) {
            EditPoint cursor = textDocument.EndPoint.CreateEditPoint();
            if(cursor.AtEndOfDocument && cursor.AtStartOfLine && cursor.AtEndOfLine) {
                var backCursor = cursor.CreateEditPoint();
                backCursor.CharLeft();
                backCursor.Delete(cursor);
            }
        }

        /// <summary>
        /// Removes all end of line whitespace from the specified text document.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveEOLWhitespace(TextDocument textDocument) {
            const string pattern = @"[ \t]+\r?\n";
            string replacement = Environment.NewLine;

            TextDocumentHelper.SubstituteAllStringMatches(textDocument,pattern,replacement);
        }

        /// <summary>
        /// Removes multiple consecutive blank lines from the specified text document.
        /// </summary>
        /// <param name="textDocument">The text document to cleanup.</param>
        private static void RemoveMultipleConsecutiveBlankLines(TextDocument textDocument) {
            const string pattern = @"(\r?\n){3,}";
            string replacement = Environment.NewLine + Environment.NewLine;

            TextDocumentHelper.SubstituteAllStringMatches(textDocument,pattern,replacement);
        }

        #endregion Methods

        public static void Cleanup(TextDocument textDocument) {
            RemoveWhitespaceLogic.RemoveEOLWhitespace(textDocument);
            RemoveWhitespaceLogic.RemoveBlankLinesAtTop(textDocument);
            RemoveWhitespaceLogic.RemoveBlankLinesAtBottom(textDocument);
            RemoveWhitespaceLogic.RemoveEOFTrailingNewLine(textDocument);
            RemoveWhitespaceLogic.RemoveBlankLinesAfterAttributes(textDocument);
            RemoveWhitespaceLogic.RemoveBlankLinesAfterOpeningBrace(textDocument);
            RemoveWhitespaceLogic.RemoveBlankLinesBeforeClosingBrace(textDocument);
            RemoveWhitespaceLogic.RemoveBlankLinesBetweenChainedStatements(textDocument);
            RemoveWhitespaceLogic.RemoveMultipleConsecutiveBlankLines(textDocument);

            RemoveWhitespaceLogic.RemoveBlankLinesBeforeClosingTag(textDocument);
            RemoveWhitespaceLogic.RemoveBlankSpacesBeforeClosingAngleBracket(textDocument);



        }
    }
}